/**   
 * Copyright 2011 COMERE Harold
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package etrl.camera;

import com.google.gwt.dom.client.NativeEvent;

import etrl.core.TransformManipulator;
import etrl.vecmath.Quat4f;
import etrl.vecmath.Vector3f;

/**
 * \class FirstPersonManipulator
 * \brief Manipulates the camera at first-person point of view. 
 * - Left mouse button = rotate camera 
 * - Middle mouse button = translate camera in its XY local plane
 * - Right mouse button = translate camera on its local Z axis
 * 
 * @author harold
 * 
 */
public class FirstPersonManipulator extends TransformManipulator
{
	/**
	 * Flag indicating if the left mouse button is currently pushed.
	 */
	private boolean _leftButtonIsDown = false;
	
	/**
	 * Flag indicating if the right mouse button is currently pushed.
	 */
	private boolean _middleButtonIsDown = false;
	
	/**
	 * Flag indicating if the right mouse button is currently pushed.
	 */
	private boolean _rightButtonIsDown = false;

	/**
	 * X mouse cursor coordinate used to compute delta variation on X axis.
	 */
	private int _mX = 0;
	
	/**
	 * Y mouse cursor coordinate used to compute delta variation on Y axis.
	 */
	private int _mY = 0;

	/**
	 * \brief Initializes default TransformManipulator.
	 */
	public FirstPersonManipulator()
	{
		super();
	}

	/**
	 * {@inheritDoc}
	 */
	public void onMouseDown(NativeEvent event)
	{
		switch (event.getButton())
		{
		case NativeEvent.BUTTON_LEFT:
			_leftButtonIsDown = true;
			break;

		case NativeEvent.BUTTON_MIDDLE:
			_middleButtonIsDown = true;
			break;

		case NativeEvent.BUTTON_RIGHT:
			_rightButtonIsDown = true;
			break;
		}

		_mX = event.getClientX();
		_mY = event.getClientY();
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onMouseUp(NativeEvent event)
	{
		switch (event.getButton())
		{
		case NativeEvent.BUTTON_LEFT:
			_leftButtonIsDown = false;
			break;

		case NativeEvent.BUTTON_MIDDLE:
			_middleButtonIsDown = false;
			break;

		case NativeEvent.BUTTON_RIGHT:
			_rightButtonIsDown = false;
			break;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onMouseMove(NativeEvent event)
	{
		int mx = event.getClientX();
		int my = event.getClientY();

		int deltax = mx - _mX;
		int deltay = my - _mY;

		float sensibility = 5.f;

		if (_leftButtonIsDown)
		{
			if (deltay != 0)
				_transform.applyRotation(new Vector3f(1.f, 0.f, 0.f), -(float) deltay / (2.f * sensibility), true);
			if (deltax != 0)
				_transform.applyRotation(new Vector3f(0.f, 1.f, 0.f), -(float) deltax / (2.f * sensibility), false);
		}

		if (_rightButtonIsDown)
		{
			if (deltay != 0)
				_transform.translateOnZAxis(-(float) deltay / (20.f * sensibility));
		}

		if (_middleButtonIsDown)
		{
			if (deltax != 0)
				_transform.translateOnXAxis(-(float) deltax / (10.f * sensibility));
			if (deltay != 0)
				_transform.translateOnYAxis((float) deltay / (10.f * sensibility));
		}

		_mX = mx;
		_mY = my;
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onMouseOut(NativeEvent event)
	{
		// When the mouse goes out of bounds, considers that all buttons are released
		_leftButtonIsDown = false;
		_middleButtonIsDown = false;
		_rightButtonIsDown = false;
	}
	
	/**
	 * {@inheritDoc}
	 */
	
	public void onMouseWheel(NativeEvent event)
	{
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onKeyDown(NativeEvent event)
	{
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onKeyUp(NativeEvent event)
	{
	}

	/**
	 * {@inheritDoc}
	 */
	
	public void onFrameEvent()
	{
	}

	/**
	 * \brief Changes the camera position.
	 * @param[in] position The new position to set.
	 */
	public void setPosition(Vector3f position)
	{
		_transform.setPosition(position);
	}

	/**
	 * \brief Changes the camera orientation.
	 * @param[in] orientation The new orientation to set.
	 */
	public void setOrientation(Quat4f orientation)
	{
		_transform.setOrientation(orientation);
	}

}
